import FUtils from 'fo-utils';
import Map from './Map';

const LAST_VERSION = "1.4.15";
const UI_LAST_VERSION = "1.0";
const BASE_URL = "https://webapi.amap.com/maps?v={0}&key={1}&callback={2}";
const UI_URL = "https://webapi.amap.com/ui/{0}/main.js?";
const SCRIPT_ID = "f-amap-core";
const UI_SCRIPT_ID = "f-amap-ui";
const CALLBACK_NAME = "_f_amap_utils_init";
if (!FUtils.BrowserUtils.inBrowser) {
    throw new Error("This script must be used in the browser.");
}

const FAMap = {
    AMap: null,
    AMapUI: null,

    isLoaded: false,
    isLoadedUI: false,

    __loadThread__: null,
    __loadUIThread__: null,

    __amapLoadedResolve: null,

    /**
     * ui 库
     */
    ui: {
        components: {
            loaded: {
                SimpleMarker: false,
                BasicControl: false
            },
            cache: {
                SimpleMarker: null,
                BasicControl: null
            },
            __loadUI__(component, path) {
                let resolveFun = resolve => {
                    if (FAMap.ui.components.loaded[component]) {
                        resolve(FAMap.ui.components.cache[component]);
                        return;
                    }
                    FAMap.AMapUI.loadUI(path, Component => {
                        FAMap.ui.components.loaded[component] = true;
                        FAMap.ui.components.cache[component] = Component;
                        resolve(Component);
                    });
                };
                if (FAMap.isLoadedUI) {
                    return new Promise(resolveFun).then(Component => {
                        Map.ui[component] = Component;
                    });
                }
                if (FAMap.__loadUIThread__) {
                    return FAMap.__loadUIThread__.then(() => {
                        return new Promise(resolveFun);
                    }).then(Component => {
                        Map.ui[component] = Component;
                    });
                }
                throw new Error("The script of ui hasn't been loaded yet!");
            }
        },
        loadSimpleMarker() {
            return FAMap.ui.components.__loadUI__("SimpleMarker", "overlay/SimpleMarker");
        },
        loadBasicControl() {
            return FAMap.ui.components.__loadUI__("BasicControl", "control/BasicControl");
        }
    },

    /**
     * 插件库
     */
    plugin: {
        components: {
            loaded: {
                Geolocation: false
            },
            cache: {
                Geolocation: null
            }
        },
        __load__(plugin, path) {
            let resolveFun = resolve => {
                if (FAMap.plugin.components.loaded[plugin]) {
                    resolve(FAMap.ui.components.cache[plugin]);
                    return;
                }
                FAMap.AMap.plugin(path, () => {
                    FAMap.ui.components.loaded[plugin] = true;
                    FAMap.ui.components.cache[plugin] = FAMap.AMap[plugin];
                    resolve(FAMap.ui.components.cache[plugin]);
                });
            };
            if (FAMap.isLoaded) {
                return new Promise(resolveFun);
            }

            if (FAMap.__loadThread__) {
                return FAMap.__loadThread__.then(() => {
                    return new Promise(resolveFun);
                });
            }

            throw new Error("The script hasn't been loaded yet!");
        },
        loadGeolocation() {
            return FAMap.plugin.__load__('Geolocation', 'AMap.Geolocation')
                .then(Geolocation => {
                    Map.plugin['Geolocation'] = Geolocation;
                    return Geolocation;
                });
        }
    },
    /**
     * 创建地图
     * @param dom 容器的dom节点
     * @param option 高德配置
     * @returns {Promise<Map>}
     */
    createMap(dom, option = {
        resizeEnable: true
    }) {
        if (!dom || !FUtils.BrowserUtils.isHTMLElement(dom)) {
            throw new Error("The arg of dom doesn't a HTMLElement!");
        }
        if (FAMap.isLoaded) {
            return new Promise(resolve => {
                resolve(new Map(new FAMap.AMap.Map(dom), dom));
            });
        }
        if (FAMap.__loadThread__) {
            return FAMap.__loadThread__.then(() => {
                return new Map(new FAMap.AMap.Map(dom, option), dom);
            });
        }
        throw new Error("The script hasn't been loaded yet!");
    },
    /**
     * 异步加载脚本
     * @param apiKey 申请的秘钥
     * @param version 版本号
     * @returns {Promise<unknown>}
     */
    asyncLoad(apiKey, version) {
        if (FAMap.isLoaded || FAMap.__loadThread__) {
            throw new Error("It's already loaded or loading now.");
        }
        if (FAMap._existScript() || (window.AMap && typeof window.AMap.Map === 'function')) {
            FAMap.__loadThread__ = new Promise(resolve => {
                FAMap.__amapLoadedResolve = resolve;
                FAMap._loaded();
            });
            return FAMap.__loadThread__;
        }

        FAMap.__loadThread__ = new Promise(resolve => {
            let url = FUtils.StringUtils.format(BASE_URL, [
                version ? version : LAST_VERSION,
                apiKey,
                CALLBACK_NAME
            ]);
            FAMap.__amapLoadedResolve = resolve;
            FUtils.ScriptUtils.loadScript(url).then(event => {
                event.srcElement.id = SCRIPT_ID;
            });
        });
        return FAMap.__loadThread__;
    },

    /**
     * 异步加载UI脚本
     * @param version 版本号
     * @returns {Promise<unknown>}
     */
    asyncLoadUI(version = UI_LAST_VERSION) {
        //校验是否已有存在的加载项
        if (FAMap.isLoadedUI || FAMap.__loadUIThread__) {
            throw new Error("It's already loaded or loading now.");
        }
        //校验是否已经存在Script
        if (FAMap._existUIScript() || (window.AMapUI && typeof window.AMapUI.loadUI === 'function')) {
            FAMap.__loadUIThread__ = new Promise(resolve => {
                FAMap._loadedUI(window.AMapUI);
                resolve(window.AMapUI);
            });
            return FAMap.__loadUIThread__;
        }
        //需要进行加载
        //校验是否含有前置加载需求
        if (!FAMap.isLoaded && !FAMap.__loadThread__) {
            throw new Error("The script hasn't been loaded yet!");
        }
        let resolveFun = resolve => {
            let url = FUtils.StringUtils.format(UI_URL, [version]);
            FUtils.ScriptUtils.loadScript(url).then(event => {
                FAMap._loadedUI(window.AMapUI);
                event.srcElement.id = UI_SCRIPT_ID;
                resolve(window.AMapUI);
            });
        };

        if (!FAMap.isLoaded && FAMap.__loadThread__) {
            return FAMap.__loadThread__.then(() => {
                FAMap.__loadUIThread__ = new Promise(resolveFun);
                return FAMap.__loadUIThread__;
            });
        }
        FAMap.__loadUIThread__ = new Promise(resolveFun);
        return FAMap.__loadUIThread__;
    },

    _existScript() {
        return Boolean(document.getElementById(SCRIPT_ID));
    },
    _existUIScript() {
        return Boolean(document.getElementById(UI_SCRIPT_ID));
    },
    _loaded() {
        FAMap.AMap = window.AMap;
        Map.install(FAMap.AMap);
        FAMap.isLoaded = true;
        FAMap.__amapLoadedResolve(window.AMap);
    },
    _loadedUI(AMapUI) {
        FAMap.AMapUI = AMapUI;
        FAMap.isLoadedUI = true;
    }
};
window[CALLBACK_NAME] = FAMap._loaded;

export default FAMap;